<?php
namespace Monkey;

/**
 * 模板引擎\Monkey\Template
 * @package    Monkey
 * @author     HuangYi
 * @copyright  Copyright (c) 2011-07-01——2013-03-30
 * @license    New BSD License
 * @version    $Id: \Monkey\Template.php 版本号 2013-03-30 $
 */
class Template {
    private $_tagCallback=array();
    private $_tag=array();
    private $_tplRoot; //模板根目录
    private $_tplCompiledRoot; //模板编译后根目录
    private $_variable = array(); //存放变量信息
    private $_label;
    /**
     * 模板解析
     * @param string $tplRoot 模板根目录
     * @param string $type 模板方案，目前支持monkeyLabel方案，你可以方便的添加
     */
    public function __construct($tplRoot, $type=null) {
        if($tplRoot){
            $this->_tplRoot=dirFormat($tplRoot);
        }  else {
            $this->_tplRoot=SYSTEM.'/template';
        }
        $tpl_compiled_root=str_replace(SYSTEM, TEMP,$this->_tplRoot).'Compiled';
        $this->_tplCompiledRoot =$this->_checkPath($tpl_compiled_root);
        $this->_tplRoot = $this->_checkPath( $this->_tplRoot);
        $this->_label = $type?$type:oApp()->labelSet;
    }
    /**
     * 模板赋值
     * @param string $name 变量名
     * @param mixed $value 变量值
     * @return $this
     */
    public function assign($name, $value) {
        $this->_variable[$name] = $value;
        return $this;
    }
    /**
     * 载入并显示模板
     * @param string $tplFileName 模板文件，相对于$tplRoot。
     */
    public function display($tplFileName){
        $this->loading($tplFileName,true);
    }
    /**
     * 载入模板
     * @param string $tplFileName  相对于模板根目录的文件名
     * @param bool $display  是否直接显示，默认为否
     * @return void|string 当直接显示时无返回，关闭显示后返回字符串
     */
    public function loading($tplFileName,$display=FALSE) {
        $tpl_file = $this->_getTplFile($tplFileName);
        $this->_checkTplFile($tpl_file);
        $tpl_compiled_file = $this->_getTplCompiledFile($tplFileName);
        if ( DEBUG
                || !file_exists($tpl_compiled_file)
                || (filemtime($tpl_compiled_file) < filemtime($tpl_file))
        ){
            $label='Monkey\\Label\\'.$this->_label;
            //import(dirname(__FILE__).'/label/'.$this->_label.'.class.php');
            $this->_tag=call_user_func(array($label,'replaceTag'));
            $this->_tagCallback=call_user_func(array($label,'callbackTag'));
            $tpl_compiled = $this->_compile($tplFileName); //获取经编译后的内容
            $dir = dirname($tpl_compiled_file);
            dirCheck($dir);//保证编译后目录存在
            file_put_contents($tpl_compiled_file, $tpl_compiled, LOCK_EX);
        }
        //解析变量
        extract($this->_variable, EXTR_OVERWRITE);
        //执行模板
        if($display){
            include $tpl_compiled_file;
        }  else {
            ob_start();
            include $tpl_compiled_file;
            return ob_get_clean();
        }
    }
    /**
     * 清空当前模板根目录下的编译缓存
     * @return $this
     */
    public function clearCompiled() {
        dirDelete($this->_tplCompiledRoot);
        return $this;
    }
    //辅助方法
    protected function _checkPath($path) {
        if(substr($path, -1) == '/')$path = substr($path, 0,-1) ;
        dirCheck($path);
        return $path;
    }
    protected function _getTplFile($file_name) {
        $file_name[0]!='/' and $file_name='/'.$file_name;
        return $this->_tplRoot . $file_name;
    }
    private function _getTplCompiledFile($file_name) {
        $file_name[0]!='/' and $file_name='/'.$file_name;
        return $this->_tplCompiledRoot . $file_name . '.php';
    }
    //用来检测模板文件是否存在
    protected function _checkTplFile($tpl_file) {
        if (!file_exists($tpl_file)){
            \MonkeyException::halt( ':模板文件【' . $tpl_file . '】不存在');
        }
    }
    //编译模板
    private function _compile($file_name) {
        $tpl_file = $this->_getTplFile($file_name);
        $this->_checkTplFile($tpl_file);
        $template = file_get_contents($tpl_file); //读取模板内容
        //解析直接替换标签
        foreach ($this->_tag as $tag) {
            $template = preg_replace($tag[0],$tag[1],$template);
        }
        //解析回调替换标签
        foreach ($this->_tagCallback as $tag) {
            $template = preg_replace_callback($tag[0],$tag[1],$template);
        }
        //解析模板包含（两种方式）
        //{include="/admin/channel_index.htm"}
        $template = preg_replace_callback('/{include=(\'|")(\S+)\1}/i',array($this,'_inc_tpl'),$template);
        //<!-- #include file="/admin/channel_index.htm" --> （兼容Dreamweaver引入文件语法）
        $template = preg_replace_callback('/<!-- #include file=(\'|")(\S+)\1 -->/i', array($this,'_inc_tpl'), $template);
        //去掉剩余的注释，提高加载速度
        $template = preg_replace("/<!--(.+?)-->/s", '', $template);
        return $template;
    }
    private function _inc_tpl($matches){
        return $this->_compile($matches[2]);
    }
}